package com.reactnativestudy.activity;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.util.Log;


import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import com.reactnativestudy.ApiInterface;
import com.reactnativestudy.BuildConfig;
import com.reactnativestudy.utils.ReactViewCache;
import com.reactnativestudy.model.DownloadBundle;
import com.reactnativestudy.model.ReactBundle;
import com.reactnativestudy.utils.Utils;

import net.lingala.zip4j.exception.ZipException;

import org.json.JSONException;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Executors;

import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import okhttp3.ResponseBody;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class SplashActivity extends AppCompatActivity {

    private static final String TAG = "SplashActivity";
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(BuildConfig.BUNDLE_URL)
            .callbackExecutor(Executors.newSingleThreadExecutor())
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .build();

    ApiInterface request = retrofit.create(ApiInterface.class);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        setContentView(R.layout.activity_splash);
        checkConfig();
    }



    private void checkConfig() {
        try {
            String entry = Utils.getItem(getApplicationContext(), "entry");
            if (entry != null && !entry.isEmpty()) {

                ReactBundle bundle = ReactBundle.toObject(entry);
                List<ReactBundle> list = checkBundle(bundle);
                Log.v(TAG, list.size() + "---");
                if (list.size() == 0){
                    ReactViewCache.getInstance().init(this,"entry", bundle);
                    start();
                }else {
                    Observable.fromIterable(list).flatMap((Function<ReactBundle, ObservableSource<DownloadBundle>>) reactBundle -> {
                        Observable<ReactBundle> obs1 = Observable.just(reactBundle);
                        Observable<ResponseBody> obs2 = request.download(reactBundle.getBundle());
                        return Observable.zip(obs1, obs2, (reactBundle1, responseBody) -> new DownloadBundle(reactBundle1, responseBody));
                    }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<DownloadBundle>() {
                        @Override
                        public void onSubscribe(Disposable d) {

                        }

                        @Override
                        public void onNext(DownloadBundle o) {
                            Log.v(TAG, "onNext");
                            ReactBundle reactBundle = o.getBundle();
                            ResponseBody responseBody = o.getResponseBody();
                            String unZipPath = Utils.getCachePath(getApplication()) + "/" + reactBundle.getHash();
                            String path = Utils.getCachePath(getApplication()) + "/" + reactBundle.getHash() + ".zip";
                            try {
                                Utils.writeFileFromBytesByStream(path, responseBody.bytes(), false);
                                Utils.unZip(unZipPath, path);
                            } catch (IOException e) {
                                e.printStackTrace();
                            } catch (ZipException e) {
                                e.printStackTrace();
                            }

                        }

                        @Override
                        public void onError(Throwable e) {

                        }

                        @Override
                        public void onComplete() {
                            Log.v(TAG, "onComplete");
                            ReactViewCache.getInstance().init(SplashActivity.this,"entry", bundle);
                            start();

                        }
                    });
                }
            } else {
                request.getConfig(BuildConfig.BUNDLE_URL)
                        .subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe(new Observer<ReactBundle>() {
                            @Override
                            public void onSubscribe(Disposable d) {
                            }

                            @Override
                            public void onNext(ReactBundle reactBundle) {
                                Utils.setItem(getApplicationContext(), "entry", reactBundle.toString());
                                checkConfig();
                            }

                            @Override
                            public void onError(Throwable e) {

                            }

                            @Override
                            public void onComplete() {

                            }
                        });
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }

    }

    private boolean checkBundlePath(ReactBundle reactBundle) {
        String cachePath = Utils.getCachePath(getApplication()) + "/";
        if (Utils.isExists(cachePath + reactBundle.getHash()) && Utils.isExists(cachePath + reactBundle.getHash() + "/" + reactBundle.getEntry())) {
            return true;
        }
        return false;
    }

    private List<ReactBundle> checkBundle(ReactBundle reactBundle) {
        List<ReactBundle> dependencies = reactBundle.getDependencies();
        List<ReactBundle> failDependencies = new ArrayList<>();
        if (dependencies != null) {
            for (int i = 0; i < dependencies.size(); i++) {
                ReactBundle b = dependencies.get(i);
                List<ReactBundle> list = checkBundle(b);
                failDependencies.addAll(list);
            }
        }
        if (!checkBundlePath(reactBundle)) {
            failDependencies.add(reactBundle);
        }
        return failDependencies;
    }

    void start() {
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                Intent intent = new Intent(SplashActivity.this, TestActivity.class);
                startActivity(intent);
                SplashActivity.this.finish();
            }
        }, 1000);
    }
}
